Function.RegisterNamespace("System.Web.EventStrategy");

System.Web.EventStrategy.Standard=function(){
    // Private Members
    var _eventMap;
    var _eventModules={
        HTMLEvents:"HTMLEvents",
        MouseEvents:"MouseEvents",
        MutationEvents:"MutationEvents",
        UIEvents:"UIEvents"
    };
    
    // ctor
    function EventManager(){
        _eventMap={};
        Array.ForEach(["abort","blur","change","error","focus","load","reset","resize","scroll","select","submit","unload"],eventModulePredicate,null,{module:_eventModules.HTMLEvents});
        Array.ForEach(["click", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup"],eventModulePredicate,null,{module:_eventModules.MouseEvents});
        Array.ForEach(["DOMAttrModified","DOMNodeInserted","DOMNodeRemoved","DOMCharacterDataModified","DOMNodeInsertedIntoDocument","DOMNodeRemovedFromDocument","DOMSubtreeModified"],eventModulePredicate,null,{module:_eventModules.MutationEvents});
        Array.ForEach(["DOMActivate","DOMFocusIn","DOMFocusOut","keydown","keypress","keyup"],eventModulePredicate,null,{module:_eventModules.UIEvents});
    }
    EventManager.apply(this,arguments);
    
    // IEventStrategy Methods
    this.Add=function(node,type,handler){
        node.addEventListener(normalizeType(type),handler,false);
    };
    
    this.Fire=function(node,type,context){
        var evtContext=context||{};
        type=normalizeType(type);
        var eventObj=document.createEvent(_eventMap[type]);
        switch(_eventMap[type]){
            case _eventModules.HTMLEvents:
                eventObj.initEvent(
                    type,
                    evtContext.CanBubble||null,
                    evtContext.IsCancelable||null
                );
                break;
            case _eventModules.MouseEvents:
                eventObj.initMouseEvent(
                    type,
                    evtContext.CanBubble||null,
                    evtContext.IsCancelable||null,
                    evtContext.Window||null, 
                    evtContext.Detail||null, 
                    evtContext.ScreenX||null, 
                    evtContext.ScreenY||null, 
                    evtContext.ClientX||null, 
                    evtContext.ClientY||null, 
                    evtContext.CtrlKey||null, 
                    evtContext.AltKey||null, 
                    evtContext.ShiftKey||null, 
                    evtContext.MetaKey||null, 
                    evtContext.Button||null, 
                    evtContext.RelatedTarget||null
                )
                break;
            case _eventModules.MutationEvents:
                eventObj.initMutationEvent(
                    type, 
                    evtContext.CanBubble||null, 
                    evtContext.IsCancelable||null, 
                    evtContext.RelatedNode||null, 
                    evtContext.PrevValue||null, 
                    evtContext.NewValue||null, 
                    evtContext.AttrName||null, 
                    evtContext.AttrChange||1
                )
                break;
            case _eventModules.UIEvents:
                eventObj.initUIEvent(
                    type, 
                    evtContext.CanBubble||null, 
                    evtContext.IsCancelable||null, 
                    evtContext.Window, 
                    evtContext.Detail
                );
                break;
            default:
                break;            
        }
        node.dispatchEvent(eventObj);
    };
    
    this.Kill=function(event){
        event.preventDefault();
    };
    
    this.Remove=function(node,type,handler){
        node.removeEventListener(normalizeType(type),handler,false);
    };

    this.Suppress=function(event){
        event.stopPropagation();
    };

    this.Target=function(event){
        return event.target;
    };
    
    // IStrategySpecification Members
    this.IsSatisfiedBy=function(candidate){
        return Object.IsType(Function,candidate.addEventListener);
    };

    // Private Methods
    function normalizeType(type){
        return type.toString().toLowerCase().replace(/^on/i,'');
    }
    
    // Predicates
    function eventModulePredicate(type,context){
        _eventMap[type]=context.module;
    }
};

System.Web.EventStrategy.Standard.Implement(System.Web.Event.IEventStrategy,"System.Web.EventStrategy.Standard");
System.Web.EventStrategy.Standard.Implement(System.Script.Strategy.IStrategySpecification,'System.Web.EventStrategy.Standard');